//|||||||||||||||||||||||||||||||||||||||||||||||

#include "GameState.hpp"
#include "OgreManualObject.h"
#include "BasePlayer.h"
#include "BaseWall.h"
#include "BtOgrePG.h"
#include "BtOgreGP.h"
#include "BtOgreExtras.h"
#include "OgreConsole.h"
#include "ProjectileManager.h"
#include "PhysicsManager.h"

//|||||||||||||||||||||||||||||||||||||||||||||||


/*
 * =====================================================================================
 *    Namespace:  Globals
 *  Description:  A dirty 'globals' hack.
 * =====================================================================================
 */

using namespace Ogre;

//|||||||||||||||||||||||||||||||||||||||||||||||

GameState::GameState()
{
    m_bLMouseDown       = false;
    m_bRMouseDown       = false;
    m_bQuit             = false;
    m_bSettingsMode     = false;

    m_pDetailsPanel		= 0;

	//OgreConsole::getSingleton().addCommand("quit",&CMD_Quit);
	//OgreConsole::getSingleton().addCommand("screenshot",&CMD_Screenshot);
}

GameState::~GameState()
	{
		// Clean up behind ourselves like good little programmers
		//Free Bullet stuff
		//delete phyWorld;
		//m_pSceneMgr->destroyCamera(m_pCamera);
		//m_pSceneMgr->destroyQuery(m_pRSQ);
		
		//if(m_pSceneMgr)
			//OgreFramework::getSingletonPtr()->m_pRoot->destroySceneManager(m_pSceneMgr);
	  
		//OgreConsole::getSingleton().shutdown();
      // delete mSolver;
      // delete mDispatcher;
      // delete mCollisionConfig;
      // delete mBroadphase;
	}

//|||||||||||||||||||||||||||||||||||||||||||||||

void GameState::enter()
{
    OgreFramework::getSingletonPtr()->m_pLog->logMessage("Entering GameState...");

    m_pSceneMgr = OgreFramework::getSingletonPtr()->m_pRoot->createSceneManager(ST_GENERIC, "GameSceneMgr");
    m_pSceneMgr->setAmbientLight(Ogre::ColourValue(0.7f, 0.7f, 0.7f));

    m_pRSQ = m_pSceneMgr->createRayQuery(Ray());
   // m_pRSQ->setQueryMask(OGRE_HEAD_MASK);

    m_pCamera = m_pSceneMgr->createCamera("GameCamera");
    m_pCamera->setPosition(Vector3(5, 60, 60));
    m_pCamera->lookAt(Vector3(5, 20, 0));
    m_pCamera->setNearClipDistance(5);

    m_pCamera->setAspectRatio(Real(OgreFramework::getSingletonPtr()->m_pViewport->getActualWidth()) /
        Real(OgreFramework::getSingletonPtr()->m_pViewport->getActualHeight()));

    OgreFramework::getSingletonPtr()->m_pViewport->setCamera(m_pCamera);
    m_pCurrentObject = 0;

    buildGUI();

	new PhysicsManager();
	PhysicsManager::getSingleton();

	new ProjectileManager(m_pSceneMgr);
	ProjectileManager::getSingleton();

	new OgreConsole;
	OgreConsole::getSingleton().init(OgreFramework::getSingletonPtr()->m_pRoot);
	OgreConsole::getSingleton().setVisible(false);

    createScene();
}

//|||||||||||||||||||||||||||||||||||||||||||||||

bool GameState::pause()
{
    OgreFramework::getSingletonPtr()->m_pLog->logMessage("Pausing GameState...");

    return true;
}

//|||||||||||||||||||||||||||||||||||||||||||||||

void GameState::resume()
{
    OgreFramework::getSingletonPtr()->m_pLog->logMessage("Resuming GameState...");

    buildGUI();

    OgreFramework::getSingletonPtr()->m_pViewport->setCamera(m_pCamera);
    m_bQuit = false;
}

//|||||||||||||||||||||||||||||||||||||||||||||||

void GameState::exit()
{
    OgreFramework::getSingletonPtr()->m_pLog->logMessage("Leaving GameState...");

	OgreConsole::getSingleton().shutdown();

    m_pSceneMgr->destroyCamera(m_pCamera);
    m_pSceneMgr->destroyQuery(m_pRSQ);
    if(m_pSceneMgr)
        OgreFramework::getSingletonPtr()->m_pRoot->destroySceneManager(m_pSceneMgr);

}

//|||||||||||||||||||||||||||||||||||||||||||||||

void GameState::createScene()
{
    m_pSceneMgr->setAmbientLight(Ogre::ColourValue(0.25, 0.25, 0.25));
    m_pSceneMgr->setShadowTechnique(Ogre::SHADOWTYPE_STENCIL_ADDITIVE);

	Ogre::Light* pointLight = m_pSceneMgr->createLight("pointLight");
   pointLight->setType(Ogre::Light::LT_POINT);
	pointLight->setPosition(Ogre::Vector3(250, 150, 250));
	pointLight->setDiffuseColour(Ogre::ColourValue::White);
	pointLight->setSpecularColour(Ogre::ColourValue::White);

	 pointLight->setDiffuseColour(1, 1, 1);
     pointLight->setSpecularColour(1, 1, 1);


	//m_pSceneMgr->setSkyDome(true, "SpaceBattle/SkyBoxOne", 5, 8);
	BasePlayer* player = new BasePlayer("One", Player_One, Ogre::ColourValue(0.08f,0.78f,0.09f,1.0f), Vector3(30, 0, -25), m_pSceneMgr);
	m_Players.push_back(player);

	OgreFramework::getSingletonPtr()->m_pViewport->setCamera(player->m_PlayerCamera);

	//BasePlayer* playerTwo = new BasePlayer("Two", Player_Two, Ogre::ColourValue(0.73f,0.13f,0.92f,1.0f), Vector3(-30, 0, -25), m_pSceneMgr);
	//playerTwo->m_PlayerShip->m_ShipNode->setPosition(Vector3(0, 5, -15));
	//m_Players.push_back(playerTwo);

	m_TargetPlane = Ogre::Plane(Ogre::Vector3::UNIT_Y, 0);

	Ogre::Plane plane(Ogre::Vector3::UNIT_Y, -10);

    Ogre::MeshManager::getSingleton().createPlane("ground", Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME,
        plane, 500, 500, 100, 100, true, 1, 5, 5, Ogre::Vector3::NEGATIVE_UNIT_Z);
	
    Ogre::Entity* entGround = m_pSceneMgr->createEntity("grid", "ground");
    m_pSceneMgr->getRootSceneNode()->createChildSceneNode()->attachObject(entGround);

    entGround->setMaterialName("SpaceBattle/Grid");
    entGround->setCastShadows(true);

	m_pSceneMgr->setSkyBox(true, "SpaceBattle/SkyBoxOne", 5000, false);

   // Ogre::Entity* ent_grid = m_pSceneMgr->createEntity("grid", "GridPlane");
   // ent_grid->setMaterialName("backgrounds/grid");
    //m_pSceneMgr->getRootSceneNode()->createChildSceneNode()->attachObject(ent_grid);

	//createGrid(500, 500, 1, 0.1);

	//OgreFramework::getSingletonPtr()->m_pTrayMgr->hideCursor();

	/*
	//Create Bullet stuff.
    mBroadphase = new btAxisSweep3(btVector3(-10000,-10000,-10000), btVector3(10000,10000,10000), 1024);
    mCollisionConfig = new btDefaultCollisionConfiguration();
    mDispatcher = new btCollisionDispatcher(mCollisionConfig);
    mSolver = new btSequentialImpulseConstraintSolver();

       //Create DebugDrawer.
    phyWorld = new btDiscreteDynamicsWorld(mDispatcher, mBroadphase, mSolver, mCollisionConfig);
    phyWorld->setGravity(btVector3(0,0,0));
	*/
	//for(int i = 0; i < 2; ++i)
	//{
		//PhysicsManager::getSingletonPtr()->add->addRigidBody(m_Players[i]->m_PlayerShip->m_ShipBody);
		//PhysicsManager::getSingletonPtr()->addPhysicsObject(m_Players[i]->m_PlayerShip->m_ShipBody);
	//}

    //Create the ground plane shape.
    //mGroundShape = new btStaticPlaneShape(btVector3(0,0,0), -40);

    //Create MotionState (no need for BtOgre here, you can use it if you want to though).
    //groundState = new btDefaultMotionState(btTransform(btQuaternion(0,0,0,1),btVector3(0,-1,0))); 

    //Create the Body.
    //mGroundBody = new btRigidBody(0, groundState, mGroundShape, btVector3(0,0,0));
    //phyWorld->addRigidBody(mGroundBody);

	

	//BaseWall* wall = new BaseWall("WallOne", Vector3(50, 20, 1), Vector3(0, 10, -50), m_pSceneMgr);
	//m_Walls.push_back(wall);


	//for(int i = 0; i < 1; ++i)
	//{
		//phyWorld->addRigidBody(m_Walls[i]->m_WallBody);
	//}
}

//|||||||||||||||||||||||||||||||||||||||||||||||

bool GameState::keyPressed(const OIS::KeyEvent &keyEventRef)
{
    if(OgreFramework::getSingletonPtr()->m_pKeyboard->isKeyDown(OIS::KC_ESCAPE))
    {
        pushAppState(findByName("PauseState"));
        return true;
    }

    if(OgreFramework::getSingletonPtr()->m_pKeyboard->isKeyDown(OIS::KC_C))
    {
		OgreConsole::getSingleton().setVisible(!(OgreConsole::getSingleton().isVisible()));
	}

	if(OgreFramework::getSingletonPtr()->keyReleased(keyEventRef))
	{
		if(keyEventRef.key == OIS::KC_M)
		{
			m_Players[0]->changeDebugVisibility();
		}
	}

    return true;
}

//|||||||||||||||||||||||||||||||||||||||||||||||

bool GameState::keyReleased(const OIS::KeyEvent &keyEventRef)
{
    OgreFramework::getSingletonPtr()->keyPressed(keyEventRef);
    return true;
}

//|||||||||||||||||||||||||||||||||||||||||||||||

bool GameState::mouseMoved(const OIS::MouseEvent &evt)
{
    if(OgreFramework::getSingletonPtr()->m_pTrayMgr->injectMouseMove(evt)) return true;

	// CEGUI::MouseCursor::getSingleton().hide();

		// get window height and width
   Ogre::Real screenWidth = Ogre::Root::getSingleton().getAutoCreatedWindow()->getWidth();
   Ogre::Real screenHeight = Ogre::Root::getSingleton().getAutoCreatedWindow()->getHeight();
 
   // convert to 0-1 offset
   Ogre::Real offsetX = evt.state.X.abs / screenWidth;
   Ogre::Real offsetY = evt.state.Y.abs / screenHeight;
   m_Players[0]->updateCamera((Degree(-evt.state.X.rel * 0.5f)), (Degree(-evt.state.Y.rel * 0.5f)));
	for(int i = 0; i < 1; ++i)
	{
		 
   // set up the ray
   Ray mouseRay = m_Players[i]->m_PlayerCamera->getCameraToViewportRay(offsetX, offsetY);
 
   // check if the ray intersects our plane
   // intersects() will return whether it intersects or not (the bool value) and
   // what distance (the Real value) along the ray the intersection is
   std::pair<bool, Real> result = mouseRay.intersects(m_TargetPlane);
 
    if(result.first) {
           // if the ray intersect the plane, we have a distance value
           // telling us how far from the ray origin the intersection occurred.
           // the last thing we need is the point of the intersection.
           // Ray provides us getPoint() function which returns a point
           // along the ray, supplying it with a distance value.
 
           // get the point where the intersection is
       Vector3 point = mouseRay.getPoint(result.second);
 
           // position our ninja to that point  
	   m_Players[i]->updateTarget(point);
    }

		
	}

    return true;
}

//|||||||||||||||||||||||||||||||||||||||||||||||

bool GameState::mousePressed(const OIS::MouseEvent &evt, OIS::MouseButtonID id)
{
    if(OgreFramework::getSingletonPtr()->m_pTrayMgr->injectMouseDown(evt, id)) return true;

    if(id == OIS::MB_Left)
    {
        onLeftPressed(evt);
        m_bLMouseDown = true;

		for(int i = 0; i < 1; ++i)
		{
			m_Players[i]->firePrimaryWeapon();
		}
    }
    else if(id == OIS::MB_Right)
    {
        m_bRMouseDown = true;

		for(int i = 0; i < 1; ++i)
		{
			m_Players[i]->fireSecondaryWeapon();
		}
    }

    return true;
}

//|||||||||||||||||||||||||||||||||||||||||||||||

bool GameState::mouseReleased(const OIS::MouseEvent &evt, OIS::MouseButtonID id)
{
    if(OgreFramework::getSingletonPtr()->m_pTrayMgr->injectMouseUp(evt, id)) return true;

    if(id == OIS::MB_Left)
    {
        m_bLMouseDown = false;
    }
    else if(id == OIS::MB_Right)
    {
        m_bRMouseDown = false;
    }

    return true;
}

//|||||||||||||||||||||||||||||||||||||||||||||||

void GameState::onLeftPressed(const OIS::MouseEvent &evt)
{
	/*
    //if(m_pCurrentObject)
    //{
       // m_pCurrentObject->showBoundingBox(false);
       // m_pCurrentEntity->getSubEntity(1)->setMaterial(m_pOgreHeadMat);
    //}

    Ogre::Ray mouseRay = m_pCamera->getCameraToViewportRay(OgreFramework::getSingletonPtr()->m_pMouse->getMouseState().X.abs / float(evt.state.width),
        OgreFramework::getSingletonPtr()->m_pMouse->getMouseState().Y.abs / float(evt.state.height));
    m_pRSQ->setRay(mouseRay);
    m_pRSQ->setSortByDistance(true);

    Ogre::RaySceneQueryResult &result = m_pRSQ->execute();
    Ogre::RaySceneQueryResult::iterator itr;

    for(itr = result.begin(); itr != result.end(); itr++)
    {
        if(itr->movable)
        {
            OgreFramework::getSingletonPtr()->m_pLog->logMessage("MovableName: " + itr->movable->getName());
            m_pCurrentObject = m_pSceneMgr->getEntity(itr->movable->getName())->getParentSceneNode();
            OgreFramework::getSingletonPtr()->m_pLog->logMessage("ObjName " + m_pCurrentObject->getName());
            m_pCurrentObject->showBoundingBox(true);
            m_pCurrentEntity = m_pSceneMgr->getEntity(itr->movable->getName());
            //m_pCurrentEntity->getSubEntity(1)->setMaterial(m_pOgreHeadMatHigh);
            break;
        }
    }
	*/
}

//|||||||||||||||||||||||||||||||||||||||||||||||

void GameState::moveCamera()
{
   // if(OgreFramework::getSingletonPtr()->m_pKeyboard->isKeyDown(OIS::KC_LSHIFT))
    //    m_pCamera->moveRelative(m_TranslateVector);
   // m_pCamera->moveRelative(m_TranslateVector / 10);
}

//|||||||||||||||||||||||||||||||||||||||||||||||

void GameState::getInput()
{
    if(m_bSettingsMode == false)
    {
		//PLAYER ONER
        if(OgreFramework::getSingletonPtr()->m_pKeyboard->isKeyDown(OIS::KC_A))
            m_Players[0]->rotateLeft();

        if(OgreFramework::getSingletonPtr()->m_pKeyboard->isKeyDown(OIS::KC_D))
             m_Players[0]->rotateRight();

        if(OgreFramework::getSingletonPtr()->m_pKeyboard->isKeyDown(OIS::KC_W))
             m_Players[0]->moveUp();

        if(OgreFramework::getSingletonPtr()->m_pKeyboard->isKeyDown(OIS::KC_S))
             m_Players[0]->moveDown();
		
		if(OgreFramework::getSingletonPtr()->m_pKeyboard->isKeyDown(OIS::KC_Q))
             m_Players[0]->moveLeft();

        if(OgreFramework::getSingletonPtr()->m_pKeyboard->isKeyDown(OIS::KC_E))
             m_Players[0]->moveRight();
		
		//if(OgreFramework::getSingletonPtr()->m_pKeyboard->isKeyDown(OIS::KC_M)){
		//	m_Players[0]->changeDebugVisibility();
		//}
	}
		
}

//|||||||||||||||||||||||||||||||||||||||||||||||

void GameState::update(double timeSinceLastFrame)
{
    m_FrameEvent.timeSinceLastFrame = timeSinceLastFrame;
    OgreFramework::getSingletonPtr()->m_pTrayMgr->frameRenderingQueued(m_FrameEvent);

    if(m_bQuit == true)
    {
        popAppState();
        return;
    }

    getInput();

	for(int i = 0; i < 1; ++i)
	{
		m_Players[i]->updatePlayer(timeSinceLastFrame);
	}
	
	ProjectileManager::getSingletonPtr()->updateProjectiles(timeSinceLastFrame);
	ProjectileManager::getSingletonPtr()->updateMissiles(timeSinceLastFrame);
	PhysicsManager::getSingletonPtr()->updatePhysics(timeSinceLastFrame);
	//phyWorld->stepSimulation(timeSinceLastFrame, 10);
}

//|||||||||||||||||||||||||||||||||||||||||||||||

void GameState::buildGUI()
{
    OgreFramework::getSingletonPtr()->m_pTrayMgr->showFrameStats(OgreBites::TL_BOTTOMLEFT);
    OgreFramework::getSingletonPtr()->m_pTrayMgr->showCursor();
}

//|||||||||||||||||||||||||||||||||||||||||||||||

void GameState::itemSelected(OgreBites::SelectMenu* menu)
{
    switch(menu->getSelectionIndex())
    {
    case 0:
        m_pCamera->setPolygonMode(Ogre::PM_SOLID);break;
    case 1:
        m_pCamera->setPolygonMode(Ogre::PM_WIREFRAME);break;
    case 2:
        m_pCamera->setPolygonMode(Ogre::PM_POINTS);break;
    }
}

void GameState::createGrid(int numcols, int numrows, float spacing, float size)
{
    //ManualObject* grid = m_pSceneMgr->createManualObject("grid");            

	 Ogre::Plane plane;
    plane.normal = Ogre::Vector3::UNIT_Y;
    plane.d = 200;
    Ogre::MeshManager::getSingleton().createPlane( "GridPlane", Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME,
                                                   plane, 2500, 2500, 1, 1, false, 1, 7, 7, Ogre::Vector3::UNIT_X);

    Ogre::Entity* ent_grid = m_pSceneMgr->createEntity("grid", "GridPlane");
    ent_grid->setMaterialName("backgrounds/grid");
    m_pSceneMgr->getRootSceneNode()->createChildSceneNode()->attachObject(ent_grid);
}

//|||||||||||||||||||||||||||||||||||||||||||||||

